package net.grapsus.arduino;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

/**
 * @file ArduinoCore.java
 * @author: Mihai Moraru
 *
 * Simulation of an Arduino Lilypad (same API as an Arduino Uno)
 *
 */

public class ArduinoCore extends JFrame implements Runnable {
	public ArduinoCore()
	{
		this("Untitled");
	}
	
	public void debugInt(int i)
	{
		System.out.println("DEBUG : " + i);
	}

	public ArduinoCore(String title)
	{
		this.title = title;
		pinList = new ArrayList<ArduinoPin>();
		tfList = new ArrayList<JTextField>();
		initComponents();
	}
	/* GUI */
	public void initComponents()
	{

		rootPanel = new JPanel();
		rootPanel.setLayout(new BorderLayout());

		/* Initialize the Arduino board */
		canvas = new ArduinoCanvas();
		canvas.setLayout(new ArduinoLayout());

		/* 	Initialize each pin */
		for(int i = 0; i <= 13; ++i) {
			final ArduinoPin pin;
			JTextField tf = new JTextField();
			tf.setMinimumSize(new Dimension(80, 10));

			if(i == 3 || i == 5 || i == 6 || i == 9 || i == 10 || i == 11)
				pin = new ArduinoPWMPin(tf, pinPosition[i][0], pinPosition[i][1]);
			else pin = new ArduinoPin(tf, pinPosition[i][0], pinPosition[i][1]);

			tf.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e)
				{
					String str = ((JTextField)e.getSource()).getText();
					Double val = 0.0;
					try {
						val = Double.parseDouble(str);
					} catch (NumberFormatException nfe) {
					}
					System.err.println("Entered "+val);
					pin.setVoltage(val);
				}
			});

			pin.addMouseListener(pin);
			pinList.add(pin);
			tfList.add(tf);
			canvas.add(pin);
		}
		canvas.doLayout();
		canvas.repaint();
		
		rootPanel.add(canvas, BorderLayout.CENTER);

		/* Add right panel */
		JPanel rightPanel = new JPanel();
		rightPanel.setMinimumSize(new Dimension(200, 517));
		rightPanel.setPreferredSize(new Dimension(200, 517));
		rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.PAGE_AXIS));
		//rightPanel.add(new JButton("Click me!"));
		for(int i = 0; i <= 13; ++i) {
			JPanel panel = new JPanel();
			panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
			JLabel label = new JLabel("Pin "+i+" ");
			label.setPreferredSize(new Dimension(64, 10));
			panel.add(label);
			panel.add(tfList.get(i));
			rightPanel.add(panel);
		}

		rootPanel.add(rightPanel, BorderLayout.EAST);

		/* Prepare the window */
		this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
		this.setTitle(this.title);
		//this.setMinimumSize(new Dimension(800, 600));
		//this.setSize(new Dimension(700, 517));
		this.setContentPane(rootPanel);
		this.pack();
		this.setVisible(true);
	}

	private static double pinPosition[][] = {
		{0.5033333333, 0.0850241546},
		{0.4066666667, 0.1024154589},
		{0.3166666667, 0.1487922705},
		{0.2416666667, 0.2231884058},
		{0.1866666667, 0.3188405797},
		{0.1850000000, 0.6550724638},
		{0.2383333333, 0.7507246377},
		{0.3141666667, 0.8270531401},
		{0.4041666667, 0.8763285024},
		{0.5033333333, 0.8927536232},
		{0.6025000000, 0.8772946860},
		{0.6950000000, 0.8289855072},
		{0.7700000000, 0.7536231884},
		{0.8233333333, 0.6560386473}
	};

	private ArduinoCanvas canvas;
	private JPanel rootPanel;
	private String title;
	private ArrayList<ArduinoPin> pinList;
	private ArrayList<JTextField> tfList;

 	// (almost) implements the hardware/arduino/cores/arduino API

	/* static */
	public static final double V_HIGH = 5;
	public static final double V_LOW = 0;
	public static final double DEFAULT = V_HIGH;
	public static final double INTERNAL = 1.1;

	public static final int HIGH = 0x1;
	public static final int LOW = 0x0;

	public static final int INPUT = 0x0;
	public static final int OUTPUT = 0x1;

	/* dynamic */
	public static double reference = ArduinoCore.DEFAULT;

	public void pinMode(int pin, int mode)
	{
		System.out.println("pinMode( "+pin+", "+mode+")");
		if(pin < 0 || pin >= pinList.size())
			return;
		pinList.get(pin).pinMode(mode);
	}

	public int digitalRead(int pin)
	{
		System.out.println("digitalRead("+pin+")");
		if(pin < 0 || pin >= pinList.size())
			return 0;
		return pinList.get(pin).digitalRead();
	}

	public void digitalWrite(int pin, int val)
	{
		System.out.println("digitalWrite("+pin+", "+val+")");
		if(pin < 0 || pin >= pinList.size())
			return;
		pinList.get(pin).digitalWrite(val);
	}

	public void analogReference(int ref)
	{
		if(ref != ArduinoCore.DEFAULT && ref != ArduinoCore.INTERNAL)
			return;
		reference = ref;
	}

	public void analogWrite(int pin, int val)
	{
		//System.out.println("analogWrite("+pin+", "+val+")");
		if(pin < 0 || pin >= pinList.size())
			return;
		pinList.get(pin).analogWrite(val);
	}

	public void delay(int ms)
	{
		//System.out.println("delay("+ms+")");
		if(ms < 0)
			return;
		try {
			Thread.sleep(ms);
		} catch (InterruptedException e) {
			System.err.println(e.getMessage());
		}
	}

	/* Stuff concerning our simulator */
	public void run()
	{
		simulationOn = true;
		setup();
		while(simulationOn == true)
			loop();
	}

	public void stop()
	{
		simulationOn = false;
	}

	/* The Java equivalent of the sketch.pde has to override these */
	protected void setup()
	{
		System.out.println("setup() called from ArduinoCore. BAD!");
	}

	protected void loop()
	{
		//System.out.println("loop() called from ArduinoCore. BAD!");
	}

	boolean simulationOn = false;
}
